package edu.gatech.oad.mule.input;

import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;
import java.util.Vector;

import javax.swing.Timer;

import edu.gatech.oad.mule.input.InputEvent.ButtonPress;
import edu.gatech.oad.mule.input.interfaces.ControllerListener;
import edu.gatech.oad.mule.input.interfaces.ControllerOwner;
import edu.gatech.oad.mule.input.interfaces.ControllerOwner.InputDevice;
import edu.gatech.oad.mule.input.interfaces.InputListener;
import edu.gatech.oad.mule.model.GameStateMachine.GameState;
import edu.gatech.oad.mule.model.NewGameDriver;
import edu.gatech.oad.mule.model.interfaces.GameStateMachineListener;

/**
 * This class listens and filters user input into the game and passes the events
 * to the GameDriver to handle. It also interacts with the controller class to
 * send to the GameDriver.
 * 
 * @author Brendan McGarry, Dale Avery, D'Miria Collins, Natasha Parekh, Jaemin
 *         Park
 * @version %I%, %G%
 */

public class Input implements ControllerListener, GameStateMachineListener {

	List<Controller> controllers;
	private Vector<InputListener> _listeners;
	NewGameDriver driver;
	GameState state;
	Timer delay;
	boolean validInput;

	/**
	 * 
	 * @param owners
	 * @param listener
	 * @param frame
	 */
	public Input(NewGameDriver driver, Component frame) {
		this.driver = driver;
		controllers = new ArrayList<Controller>();

		for (ControllerOwner owner : driver.getActiveOwners()) {
			Controller controller;
			if (owner.getInputDevice() == InputDevice.KEYBOARD_STD) {
				controller = new Keyboard(owner);
				frame.addKeyListener((Keyboard) controller);
				controller.addActionListener(this);
				controllers.add(controller);
			}
		}
		
		ActionListener taskPerformer = new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                validInput = true;
                delay.stop();
                delay.restart();
            }
            };
		delay = new Timer(100, taskPerformer);
		
		validInput = true;

		// TODO figure out how to get the players set up
	}// end constructor

	@Override
	public void stateChange(GameState state) {
		this.state = state;
		System.out.println("Input register state change to: " + state);
	}

	@Override
	public void inputEventHandler(InputEvent event, Controller controller) {
		// TODO Check the state to determine if ANY input will be passed to
		// listeners.
		// TODO Get the currently valid controller owners.

		if (event.getPress() != ButtonPress.ERROR) {
			// Obtain a list of valid owners who can send input events.
			if (checkOwners(driver, controller)) {
				if (event.getPress().equals(ButtonPress.ACTION)) {
					if(validInput) {
						buttonEvent(event);
						validInput = false;
						delay.start();
					}
				} else {
					buttonEvent(event);
				}
			}
		} else {
			System.out
					.println("Input received an invalid input event from controller: "
							+ controller.toString()
							+ ".  Button press was ignored.");
		}

	}

	/**
	 * Add's a given InputListener to the list of listeners who will be notified
	 * when an input event occurs.
	 * 
	 * @param listener
	 *            The listener to be added to the list.
	 */
	public final void addActionListener(InputListener listener) {
		if (_listeners == null)
			_listeners = new Vector<InputListener>();

		_listeners.addElement(listener);
	}

	/**
	 * Sends notification to all listeners that an input event has occurred.
	 */
	protected final void buttonEvent(InputEvent event) {
		if (_listeners != null && !_listeners.isEmpty()) {
			Enumeration<InputListener> listeners = _listeners.elements();
			while (listeners.hasMoreElements()) {
				InputListener listener = (InputListener) listeners
						.nextElement();
				listener.inputEventHandler(event);
			}
		}
	}

	/**
	 * Checks a given InputListener to determine if any of its active
	 * ControllerOwners own the given controller.
	 * 
	 * @param handler
	 *            An InputListener with active ControllerOwners
	 * @param controller
	 *            A Controller with an owner.
	 * @return True if this listener has an active ControllerOwner who owns the
	 *         given controller, false otherwise.
	 */
	private final boolean checkOwners(InputListener listener,
			Controller controller) {
		ControllerOwner[] owners = listener.getActiveOwners();
		for (ControllerOwner owner : owners) {
			if (owner.equals(controller.getOwner()))
				return true;
		}
		return false;
	}
}
// http://examples.javacodegeeks.com/desktop-java/awt/event/actionlistener-example/
// http://stackoverflow.com/questions/9358710/java-action-listener-on-menu-and-not-on-menu-item
// http://stackoverflow.com/questions/9358710/java-action-listener-on-menu-and-not-on-menu-item
// input devices and number of players
// state of the game & valid inputs